﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using Lime49.UI;
using LockCrypt.DAL;
using LockCrypt.Core;

namespace LockCrypt {
    /// <summary>
    /// Window for adding groups.
    /// </summary>
    public partial class WinAddGroup : Window {
        private IGroup _group;
        private string _parent;
        private bool _editing = false;

        /// <summary>
        /// Gets the group which was saved.
        /// </summary>
        /// <value>The group which was saved.</value>
        public IGroup CurrentGroup {
            get {
                Group newGroup = new Group() {
                    Name = txtName.Text.Trim(),
                    ParentID = cboParent.SelectedIndex > 0 ? cboParent.SelectedValue.ToString() : null,
                    SortIndex = _group.SortIndex,
                    Groups = _group.Groups,
                    Accounts = _group.Accounts
                };
                if(_editing) {
                    newGroup.ID = _group.ID;  
                }
                return newGroup;
            }
        }

        /// <summary>
        /// Initializes a new <see cref="WinAddGroup"/>.
        /// </summary>
        public WinAddGroup() {
            InitializeComponent();
            _group = new Group();
        }

        /// <summary>
        /// Initializes a new <see cref="WinAddGroup"/>.
        /// </summary>
        /// <param name="parentId">The parent group ID to pre-select.</param>
        public WinAddGroup(string parentId)
            :this(){
            _parent = parentId;
        }

        /// <summary>
        /// Initializes a new <see cref="WinAddGroup"/> to edit a group.
        /// </summary>
        /// <param name="group">The group to edit.</param>
        public WinAddGroup(IGroup group) 
            :this() {
            _group = group;
            _parent = group.ParentID;
            _editing = true;
            txtName.Text = group.Name;
            Title = I18nUtils.GetString("Strings", "EditGroup");
        }

        /// <summary>
        /// Loads available parent groups when the Window loads.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void Window_Loaded(object sender, RoutedEventArgs e) {
            txtName.Focus();
            txtName.SelectAll();
            BackgroundWorker worker = new BackgroundWorker();
            worker.DoWork += (s, dwe) => {
                dwe.Result = DalConfigurationManager.Provider.GetGroups();
            };
            worker.RunWorkerCompleted += (s, rwe) => {
                if(rwe.Error != null) {
                    DialogBox.ShowAlert(this, rwe.Error, I18nUtils.GetString("Errors", "Error"));
                } else if(rwe.Result is IList<IGroup>) {
                    cboParent.IsEnabled = true;
                    List<Group> groups = (rwe.Result as IList<IGroup>).OrderBy(g => g.Name)
                                                                      .Select(g => new Group(g))
                                                                      .ToList();
                    groups.Insert(0, Group.Empty);
                    if(_editing) {
                        // a group can't be added as it's own parent or as a parent of one of it's descendant unless
                        // it like... went back in TIME or something and became it's own grandfather.
                        IEnumerable<IGroup> nestedGroups = LockCrypt.Core.LockCryptBLL.ArrangeGroups(groups.Cast<IGroup>());
                        IGroup editingGroup = null;
                        foreach(var group in nestedGroups) {
                            // search top level groups
                            editingGroup = group.FindGroup(_group.ID);
                            if(editingGroup != null)
                                break;
                        }
                        IEnumerable<Group> unavailableGroups = ((GroupBase)editingGroup).Flatten().Cast<Group>();
                        groups = groups.Except(unavailableGroups).ToList();
                    }
                    cboParent.ItemsSource = groups;
                    if(_parent != null) {
                        cboParent.SelectedValue = _parent;
                    } else {
                        cboParent.SelectedIndex = 0;
                    } 
                }
            };
            cboParent.IsEnabled = false;
            worker.RunWorkerAsync();
        }

        /// <summary>
        /// Checks the data entered is valid.
        /// </summary>
        /// <returns><c>True</c> if the data is valid, otherwise <c>false</c></returns>
        private bool Validate() {
            bool valid = true;
            if(txtName.Text.Trim().Length == 0) {
                DialogBox.ShowAlert(this, I18nUtils.GetString("Errors", "GroupNameInvalid"), I18nUtils.GetString("Errors", "Error"));
                txtName.Focus();
                valid = false;
            }
            return valid;
        }

        /// <summary>
        /// Saves the group.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void Save(object sender, ExecutedRoutedEventArgs e) {
            if(Validate()) {
                DialogResult = true;
            }
        }

        /// <summary>
        /// Closes the window.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void CloseWindow(object sender, ExecutedRoutedEventArgs e) {
            DialogResult = false;
        }
    }
}
